package cn.edu.cug.cs.gtl.oi.inventor.demo;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JEditorPane;
import javax.swing.JScrollPane;

import cn.edu.cug.cs.gtl.oi.utils.Example;
import cn.edu.cug.cs.gtl.oi.utils.ViewerComponentsFactory;
import com.openinventor.inventor.SbVec2s;
import com.openinventor.inventor.SbViewportRegion;
import com.openinventor.inventor.SoDB;
import com.openinventor.inventor.SoInput;
import com.openinventor.inventor.SoOutput;
import com.openinventor.inventor.SoPickedPoint;
import com.openinventor.inventor.actions.SoRayPickAction;
import com.openinventor.inventor.actions.SoWriteAction;
import com.openinventor.inventor.events.SoEvent;
import com.openinventor.inventor.events.SoMouseButtonEvent;
import com.openinventor.inventor.misc.callbacks.SoEventCallbackCB;
import com.openinventor.inventor.nodes.SoEventCallback;
import com.openinventor.inventor.nodes.SoMaterial;
import com.openinventor.inventor.nodes.SoRotationXYZ;
import com.openinventor.inventor.nodes.SoSeparator;
import com.openinventor.inventor.nodes.SoTranslation;
import com.openinventor.inventor.viewercomponents.awt.IViewerExaminer;
import com.openinventor.inventor.viewercomponents.nodes.SceneExaminer.InteractionMode;



public class PickAction extends Example {

    private IViewerExaminer m_myViewer;
    private Frame m_pathFrame = null;
    private String m_outFilename = "out.txt";
    private String m_inFilename = "$OIVJHOME/data/models/star2.iv";

    public static void main(String[] args) {
        PickAction example = new PickAction();
        example.demoMain("Pick Action & Paths");
    }

    @Override
    public void start() {
        m_myViewer = ViewerComponentsFactory.createViewerExaminer();

        // Add an event callback to catch mouse button presses.
        // The callback is set up later on.
        SoEventCallback myEventCB = new SoEventCallback();

        // Read object data from a file
        SoInput mySceneInput = new SoInput();
        if (!mySceneInput.openFile(m_inFilename)) {
            System.err.println("Could not open file " + m_inFilename);
            System.exit(1);
        }

        SoSeparator starObject = SoDB.readAll(mySceneInput);
        if (starObject == null) {
            System.err.println("Could not generate scene graph from file " + m_inFilename) ;
            System.exit(1);
        }
        mySceneInput.closeFile();

        // Add two copies of the star object, one white and one red
        SoRotationXYZ myRotation = new SoRotationXYZ();
        myRotation.axis.setValue(SoRotationXYZ.AxisType.X);
        myRotation.angle.setValue((float)(java.lang.Math.PI / 2.2f)); // almost 90 degrees

        SoMaterial myMaterial = new SoMaterial();
        myMaterial.diffuseColor.setValue(1.0f, 0.0f, 0.0f); // red

        SoTranslation myTranslation = new SoTranslation();
        myTranslation.translation.setValue(1.0f, 0.0f, 1.0f);

        SoSeparator root = new SoSeparator();
        { // Assemble scene graph
            root.addChild(myEventCB);
            root.addChild(myRotation);
            root.addChild(starObject); // first star object
            root.addChild(myMaterial);
            root.addChild(myTranslation);
            root.addChild(starObject); // second star object
        }

        // Turn off viewing to allow picking
        m_myViewer.getRenderArea().getSceneInteractor().setInteractionMode(InteractionMode.SELECTION);
        m_myViewer.setSceneGraph(root);
        m_myViewer.viewAll();

        // Set up the event callback
        myEventCB.addEventCallback(SoMouseButtonEvent.class, new MousePressCB());

        final Component component = m_myViewer.getComponent();
        component.setPreferredSize(new java.awt.Dimension(600, 500));
        setLayout(new BorderLayout());
        add(component);
    }

    @Override
    public void stop()
    {
        if ( m_pathFrame != null )
            m_pathFrame.dispose();
        m_myViewer.dispose();
    }

    ///////////////////////////////////////////////////////////////
    // CODE FOR The Inventor Mentor STARTS HERE

    private boolean writePickedPath(SbViewportRegion viewport, SbVec2s cursorPosition) {
        SoRayPickAction myPickAction= new SoRayPickAction(viewport);

        // Set an 8-pixel wide region around the pixel
        myPickAction.setPoint(cursorPosition);
        myPickAction.setRadius(8.0f);

        // Start a pick traversal
        myPickAction.apply(m_myViewer.getRenderArea().getSceneInteractor());
        SoPickedPoint myPickedPoint = myPickAction.getPickedPoint();
        if (myPickedPoint == null)
            return false;

        // Write out the path to the picked object
        SoOutput out = new SoOutput();
        out.openFile(m_outFilename);
        SoWriteAction myWriteAction = new SoWriteAction(out);
        myWriteAction.apply(myPickedPoint.getPath());
        out.closeFile();

        makePathFrame();
        return true;
    }
    // CODE FOR The Inventor Mentor ENDS HERE
    ///////////////////////////////////////////////////////////////

    private void makePathFrame() {
        if (m_pathFrame != null)
            m_pathFrame.dispose();

        WindowListener l = new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                e.getWindow().dispose();
            }
        };

        try {
            JEditorPane pane = new JEditorPane("file:" + m_outFilename);
            pane.setEditable(false);
            JScrollPane jsp = new JScrollPane(pane);
            jsp.setPreferredSize(new Dimension(600, 700));
            m_pathFrame = new Frame("Path");
            m_pathFrame.addWindowListener(l);
            m_pathFrame.add(jsp);
            m_pathFrame.pack();
            m_pathFrame.setVisible(true);
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

    class MousePressCB extends SoEventCallbackCB {
        @Override
        public void invoke (SoEventCallback cb) {
            SoEvent event = cb.getEvent();
            // Check for mouse button being pressed
            if (SoMouseButtonEvent.isButtonPressEvent(event, SoMouseButtonEvent.Buttons.ANY)) {
                SbViewportRegion myRegion = cb.getAction().getViewportRegion();
                writePickedPath(myRegion, event.getPosition(myRegion));
                cb.setHandled();
            }
        }
    }
}
